<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>

  <div id="app">
    <input type="text" v-model="message">
    {{message}}
  </div>

<script>
  class Vue{
    constructor(options) {
      // 1.保存数据
      this.$options = options
      this.$data = options.data()
      this.$el = options.el

      // 2.将data添加到响应式系统中
      new Observer(this.$data)

      // 3.代理this.$data的数据
      Object.keys(this.$data).forEach(key => {
        this._proxy(key)
      })

      // 4.处理el
      new Compiler(this.$el,this)
    }

    _proxy(key) {
      Object.defineProperty(this,key,{
        configurable: true,
        enumerable: true,
        set(newValue) {
          this.$data[key] = newValue
        },
        get() {
          return this.$data[key]
        }
      })
    }
  }

  class Observer {
    constructor(data) {
      this.data = data

      Object.keys(data).forEach(key => {
        this.defineReactive(this.data,key,data[key])
      })
    }

    defineReactive(data, key, val) {
      // 一个属性key -> Dep对象
      const dep = new Dep()
      Object.defineProperty(data,key,{
        enumerable: true,
        configurable: true,
        get() {
          if (Dep.target) {
            dep.addSub(Dep.target)
          }
          return val
        },
        set(newValue) {
          if (newValue === val) {
            return
          }
          val = newValue
          dep.notify()
        }
      })
    }
  }

  class Dep {
    constructor() {
      this.subs = []
    }

    addSub(sub) {
      this.subs.push(sub)
    }

    notify(){
      this.subs.forEach(sub => {
        sub.update()
      })
    }
  }

  class Watcher {
    constructor(node,name,vm) {
      this.node = node;
      this.name = name;
      this.vm = vm;
      Dep.target = this;
      this.update();
      Dep.target = null
    }

    update(){
      this.node.nodeValue = this.vm[this.name]
    }
  }

  const reg = /\{\{(.*)\}\}/
  class Compiler {
    constructor(el,vm) {
      this.el = document.querySelector(el)
      this.vm = vm

      this.frag = this._createFragment()
      this.el.appendChild(this.frag)
    }

    _createFragment(){
      const frag = document.createDocumentFragment()

      let child;
      while (child = this.el.firstChild) {
        this._compile(child)
        frag.appendChild(child)
      }
      return frag
    }

    _compile(node) {
      if (node.nodeType === 1) { // 标签结点
        const attrs = node.attributes
        if (attrs.hasOwnProperty('v-model')) {
          const name = attrs['v-model'].nodeValue
          node.addEventListener('input',e => {
            this.vm[name] = e.target.value
          })
        }
      }
      if (node.nodeType === 3) { // 文本结点
        console.log(reg.test(node.nodeValue));
        if (reg.test(node.nodeValue)) {
          const name = RegExp.$1.trim()
          console.log(name)
          new Watcher(node,name,this.vm)
        }
      }
    }
  }

</script>

<!--原生-->
<!--<script src="./node_modules/vue/dist/vue.js"></script>-->
<script>
  const app = new Vue({
    el: '#app',
    data(){
      return {
        message: '哈哈哈'
      }
    }
  })
</script>
</body>
</html>
